/*
 * Copyright (C) 2022-2022. Huawei Technologies Co., Ltd. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.openlookeng.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ssh.JschSessionPool;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jcraft.jsch.Session;
import com.openlookeng.core.boot.config.FileConfig;
import com.openlookeng.core.boot.dto.LoginUserInfoDTO;
import com.openlookeng.core.boot.jwt.model.Audience;
import com.openlookeng.core.boot.utils.Constant;
import com.openlookeng.core.boot.utils.FileUploadUtils;
import com.openlookeng.core.boot.utils.JwtTokenUtil;
import com.openlookeng.core.dto.SshUserDTO;
import com.openlookeng.core.mp.base.BaseServiceImpl;
import com.openlookeng.core.tool.ExcelUtil;
import com.openlookeng.core.tool.Md5Utils;
import com.openlookeng.core.tool.utils.DateUtil;
import com.openlookeng.core.vo.ExcelColumnVo;
import com.openlookeng.dto.ClusterEchartDTO;
import com.openlookeng.dto.EchartTimeDTO;
import com.openlookeng.dto.EcsDTO;
import com.openlookeng.entity.Ecs;
import com.openlookeng.entity.OpenlookengCluster;
import com.openlookeng.entity.OpenlookengClusterConfig;
import com.openlookeng.enums.NodeTypeEnum;
import com.openlookeng.exception.BizException;
import com.openlookeng.mapper.EcsMapper;
import com.openlookeng.mapper.OpenlookengClusterConfigMapper;
import com.openlookeng.mapper.OpenlookengClusterMapper;
import com.openlookeng.qo.DiskQo;
import com.openlookeng.qo.EcsQO;
import com.openlookeng.qo.LogFileQO;
import com.openlookeng.service.IEcsService;
import com.openlookeng.service.IOpenlookengClusterService;
import com.openlookeng.utils.LinuxShellUtils;
import com.openlookeng.utils.TreadUtils;
import com.openlookeng.vo.ClusterStateVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

@Service
@Slf4j
@CacheConfig(cacheNames = "ecsCache")
public class EcsServiceImpl
        extends BaseServiceImpl<EcsMapper, Ecs>
        implements IEcsService
{
    @Autowired
    private Audience audience;
    @Resource
    private OpenlookengClusterMapper openlookengClusterMapper;
    @Resource
    private OpenlookengClusterConfigMapper openlookengClusterConfigMapper;
    @Lazy
    @Autowired
    private IOpenlookengClusterService openlookengClusterService;
    @Lazy
    @Autowired
    private OpenlookengClusterServiceImpl openlookengClusterServiceImpl;
    @Lazy
    @Autowired
    private OpenLookengServiceImpl openLookengServiceImpl;
    @Resource
    private CacheManager cacheManager;
    @Value("${openlookeng.fileDir}")
    private String fileDir;

    @Override
    public Map uploadAndAdd(MultipartFile file, EcsDTO ecsDTO) throws Exception
    { //Add a host and modify it to fill in only one host on the page. The others are imported from excel. If it is successful, it will return to XX host. Ping is successful
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        Map<String, List<String>> exceptionMap = new LinkedHashMap();
        ArrayList<String> strings = new ArrayList<>();
        ArrayList<String> strings2 = new ArrayList<>();
        ArrayList<String> strings3 = new ArrayList<>();

        if (file != null) {
            File uploadFile = FileUploadUtils.getUploadFile(file, fileDir);
            List<ExcelColumnVo> vos = new ArrayList<>();
            vos.add(new ExcelColumnVo("主机名", "name"));
            vos.add(new ExcelColumnVo("账号", "userName"));
            vos.add(new ExcelColumnVo("密码", "passWord"));
            vos.add(new ExcelColumnVo("端口", "port"));
            vos.add(new ExcelColumnVo("管理IP", "ip"));
            vos.add(new ExcelColumnVo("业务IP", "serviceIp"));
            List<Ecs> ecss = ExcelUtil.readExcel(uploadFile, vos, Ecs.class);

            QueryWrapper<Ecs> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("create_user_id", loginUserInfoDTO.getId());
            List<Ecs> listEcs = this.baseMapper.selectList(queryWrapper);

            for (int i = 0; i < ecss.size(); i++) {
                if (ecss.get(i).getPort() == null) {
                    ecss.get(i).setPort(22);
                }
                if (StrUtil.isBlank(ecss.get(i).getName()) || StrUtil.isBlank(ecss.get(i).getUserName()) || StrUtil.isBlank(ecss.get(i).getPassWord()) || StrUtil.isBlank(ecss.get(i).getIp()) || StrUtil.isBlank(ecss.get(i).getServiceIp())) {
                    strings2.add(ecss.get(i).getIp());
                }
                else {
                    int finalI = i;
                    long count = listEcs.stream().filter(item -> item.getIp().equals(ecss.get(finalI).getIp())).count();
                    if (count == 0) {
                        //ping
                        try {
                            LinuxShellUtils.ping(ecss.get(finalI).getIp(), ecss.get(finalI).getPort());
                        }
                        catch (Exception e) {
                            strings.add(ecss.get(finalI).getIp());
                        }
                        ecss.get(finalI).setCreateUserId(Integer.valueOf(loginUserInfoDTO.getId()));
                        ecss.get(finalI).setPassWord(Md5Utils.toAes(ecss.get(finalI).getPassWord()));
                        if (strings.size() == 0) {
                            this.baseMapper.insert(ecss.get(finalI));
                        }
                        else {
                            long count1 = strings.stream().filter(item -> item.equals(ecss.get(finalI).getIp())).count();
                            if (count1 == 0) {
                                this.baseMapper.insert(ecss.get(finalI));
                            }
                        }
                    }
                    else {
                        strings3.add(ecss.get(finalI).getIp());
                    }
                }
            }
        }

        if (StrUtil.isNotBlank(ecsDTO.getName()) && StrUtil.isNotBlank(ecsDTO.getIp()) && StrUtil.isNotBlank(ecsDTO.getServiceIp()) && StrUtil.isNotBlank(ecsDTO.getPassWord()) && StrUtil.isNotBlank(ecsDTO.getUserName())) {
            QueryWrapper<Ecs> wrapper = new QueryWrapper<>();
            wrapper.eq("ip", ecsDTO.getIp());
            wrapper.eq("create_user_id", loginUserInfoDTO.getId());
            Ecs ecs = this.baseMapper.selectOne(wrapper);
            if (ObjectUtil.isEmpty(ecs)) {
                if (ecsDTO.getPort() == null) {
                    ecsDTO.setPort(22);
                }
                try {
                    LinuxShellUtils.ping(ecsDTO.getIp(), ecsDTO.getPort());
                }
                catch (Exception e) {
                    strings.add(ecsDTO.getIp());
                }
                if (strings.size() == 0) {
                    Ecs ecs1 = new Ecs();
                    ecs1.setName(ecsDTO.getName());
                    ecs1.setIp(ecsDTO.getIp());
                    ecs1.setServiceIp(ecsDTO.getServiceIp());
                    ecs1.setUserName(ecsDTO.getUserName());
                    ecs1.setPassWord(Md5Utils.toAes(ecsDTO.getPassWord()));
                    ecs1.setPort(ecsDTO.getPort());
                    ecs1.setCreateUserId(Integer.valueOf(loginUserInfoDTO.getId()));
                    this.baseMapper.insert(ecs1);
                }
            }
            else {
                strings3.add(ecsDTO.getIp());
            }
        }
        else {
            strings2.add(ecsDTO.getIp());
        }

        if (CollUtil.isNotEmpty(strings)) {
            exceptionMap.put("以下主机连接失败", strings);
        }
        if (CollUtil.isNotEmpty(strings2)) {
            exceptionMap.put("账号、密码、管理IP、业务IP不能为空", strings2);
        }
        if (CollUtil.isNotEmpty(strings3)) {
            exceptionMap.put("以下主机重复添加", strings3);
        }

        return exceptionMap;
    }

    @Override
    public Map add(List<EcsDTO> ecsDTOs)
    {
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        //emptys Excel line has empty
        Map<String, List<String>> exceptionMap = new LinkedHashMap();
        ArrayList<String> emptys = new ArrayList<>();

        LambdaQueryWrapper<Ecs> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Ecs::getCreateUserId, loginUserInfoDTO.getId());
        List<Ecs> ecsList = this.baseMapper.selectList(wrapper);
        List<Ecs> list = new ArrayList<>();
        ecsDTOs.stream().forEach(ecsDTO -> {
            if (StrUtil.isNotBlank(ecsDTO.getName()) && StrUtil.isNotBlank(ecsDTO.getIp()) && StrUtil.isNotBlank(ecsDTO.getServiceIp()) && StrUtil.isNotBlank(ecsDTO.getPassWord()) && StrUtil.isNotBlank(ecsDTO.getUserName())) {
                Ecs ecs = new Ecs();
                ecs.setName(ecsDTO.getName());
                ecs.setIp(ecsDTO.getIp());
                ecs.setServiceIp(ecsDTO.getServiceIp());
                ecs.setUserName(ecsDTO.getUserName());
                try {
                    ecs.setPassWord(Md5Utils.toAes(ecsDTO.getPassWord()));
                }
                catch (Exception e) {
                    log.error("ecs :{} set password  err:{}", ecs.getIp(), e.getMessage());
                }
                ecs.setPort(ecsDTO.getPort());
                ecs.setCreateUserId(Integer.valueOf(loginUserInfoDTO.getId()));
                list.add(ecs);
            }
            else {
                emptys.add(ecsDTO.getIp());
            }
        });
        if (CollUtil.isNotEmpty(emptys)) {
            exceptionMap.put("账号、密码、管理IP、业务IP不能为空", emptys);
        }

        ThreadUtil.execute(new Runnable() {
            @Override
            public void run()
            {
                ecsDTOs.forEach(a -> {
                    SshUserDTO sshUserDTO = new SshUserDTO();
                    sshUserDTO.setSshUser(a.getUserName());
                    sshUserDTO.setSshPass(Md5Utils.decrypt(a.getPassWord()));
                    sshUserDTO.setSshPort(a.getPort());
                    sshUserDTO.setSshHost(a.getIp());
                    LinuxShellUtils.addDefaultUser(sshUserDTO);
                });
            }
        });
        if (CollUtil.isNotEmpty(exceptionMap)) {
            return exceptionMap;
        }
        list.forEach(item -> {
            Ecs ecs = ecsList.stream().filter(ite -> ite.getIp().equals(item.getIp())).findFirst().orElse(null);
            if (ObjectUtil.isNotEmpty(ecs)) {
                item.setId(ecs.getId());
            }
        });
        this.saveOrUpdateBatch(list);
        return exceptionMap;
    }

    @Override
    public Page<Ecs> selectEcsPage(EcsQO ecs)
    {
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        Integer userId = Integer.valueOf(loginUserInfoDTO.getId());
        ecs.setCreateUserId(userId);
        QueryWrapper<Ecs> queryChainWrapper = this.getQueryChainWrapper(ecs);
        Page<Ecs> ecsPage = this.baseMapper.selectPage(new Page<>(ecs.getPageNo(), ecs.getPageSize()), queryChainWrapper);
        List<Ecs> records = ecsPage.getRecords();

        records.stream().forEach(e -> {
            e.setState(Constant.NODE_STATE_ACTIVE.getCode());
            try {
                LinuxShellUtils.ping(e.getIp(), e.getPort());
            }
            catch (Exception f) {
                e.setState(Constant.NODE_STATE_DISCONNECTION.getCode());
            }
            Map<String, String> res = this.getOsInfoFromCache(e);
            BigDecimal memTotal = BigDecimal.ZERO;
            BigDecimal memSysUsed = BigDecimal.ZERO;
            BigDecimal cpuTotalNum = BigDecimal.ZERO;
            BigDecimal cpuUsedNum = BigDecimal.ZERO;
            String diskUsed = res.getOrDefault("disk_used", "0");
            String diskTotal = res.getOrDefault("disk_total", "0");
            String[] diskUsedSplit = StrUtil.split(diskUsed, "&");
            String[] diskTotalSplit = StrUtil.split(diskTotal, "&");

            long used = 0;
            long total = 0;
            for (int i = 1; i < diskUsedSplit.length; i++) {
                used = used + Long.parseLong(diskUsedSplit[i]);
            }
            for (int i = 1; i < diskTotalSplit.length; i++) {
                total = total + Long.parseLong(diskTotalSplit[i]);
            }
            Double aDouble = openlookengClusterServiceImpl.kbToGb(String.valueOf(used));
            Double aDouble1 = openlookengClusterServiceImpl.kbToGb(String.valueOf(total));

            String cpuNum = res.getOrDefault("cpu_num", "0");
            //cpu 使用率
            String cpuUser = res.getOrDefault("cpu_user", "0");
            BigDecimal cpuNumVal = new BigDecimal(cpuNum);
            BigDecimal cpuUserVal = cpuNumVal.multiply(new BigDecimal(cpuUser)).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
            String memTotalStr = res.getOrDefault("mem_total", "0");
            Double memTotalVal = openlookengClusterServiceImpl.kbToGb(memTotalStr);
            String memSysUsedStr = res.getOrDefault("mem_sys_used", "0");
            Double memSysUsedVal = openlookengClusterServiceImpl.kbToGb(memSysUsedStr);
            memTotal = memTotal.add(BigDecimal.valueOf(memTotalVal));
            memSysUsed = memSysUsed.add(BigDecimal.valueOf(memSysUsedVal));
            cpuTotalNum = cpuTotalNum.add(cpuNumVal);
            cpuUsedNum = cpuUsedNum.add(cpuUserVal);

            e.setMemory(memSysUsedVal + "G/" + memTotalVal + "G");
            e.setMemoryUsage(String.valueOf(Math.round(memSysUsedVal / memTotalVal * 100)));

            e.setCpu(cpuUser);

            e.setDiskCapacity(aDouble + "G/" + aDouble1 + "G");
            e.setDiskOccupancy(String.valueOf(Math.round(aDouble / aDouble1 * 100)));
        });
        if (StrUtil.isNotEmpty(ecs.getRunState())) {
            List<Ecs> collect = records.stream().filter(i -> i.getState().equals(ecs.getRunState())).collect(Collectors.toList());
            ecsPage.setRecords(collect);
            ecsPage.setTotal(collect.size());
        }
        return ecsPage;
    }

    @Override
    public Ecs one(Integer id)
    {
        Ecs ecs = baseMapper.selectById(id);
        if (ObjectUtil.isEmpty(ecs)) {
            throw new BizException("主机不存在!");
        }
        QueryWrapper<OpenlookengCluster> wrapper = new QueryWrapper<>();
        wrapper.eq("ecs_id", id);
        OpenlookengCluster openlookengCluster = openlookengClusterMapper.selectOne(wrapper);

        LogFileQO logFileQO = new LogFileQO();
        ecs.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode()); //默认关闭
        if (ObjectUtil.isNotEmpty(openlookengCluster)) {
            //coordinator&worker
            NodeTypeEnum nodeTypeEnum = NodeTypeEnum.ALL.getNodeTypeEnumByType(openlookengCluster.getNodeType());
            logFileQO.setNodeType(nodeTypeEnum.getRoleName());
            logFileQO.setId(openlookengCluster.getId());

            LambdaQueryWrapper<OpenlookengClusterConfig> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(OpenlookengClusterConfig::getClusterCode, openlookengCluster.getClusterCode());
            queryWrapper.eq(OpenlookengClusterConfig::getVersion, openlookengCluster.getVersion());
            queryWrapper.eq(OpenlookengClusterConfig::getOpenlookengClusterId, openlookengCluster.getId());
            List<OpenlookengClusterConfig> clusterConfigList = openlookengClusterConfigMapper.selectList(queryWrapper);
            //coordinator
            if (Constant.NODE_TYPE_2.getCode().equalsIgnoreCase(openlookengCluster.getNodeType())) {
                try {
                    OpenlookengClusterConfig config = clusterConfigList.stream().filter(item -> Constant.HTTP_SERVER_HTTP_PORT.getCode().equalsIgnoreCase(item.getProKeyName())).findFirst().orElse(null);
                    if (ObjectUtil.isNotEmpty(config)) {
                        HttpUtil.get(ecs.getIp() + ":" + config.getProValue() + Constant.URL_STATE_SUFFIX.getCode(), 5000);
                        ecs.setState(Constant.NODE_STATE_ACTIVE.getCode());
                    }
                }
                catch (Exception e) {
                    log.info("failed to query node status,{}", e.getMessage());
                }
            }
            else {
                OpenlookengClusterConfig config = clusterConfigList.stream().filter(item -> Constant.DISCOVERY_URI.getCode().equalsIgnoreCase(item.getProKeyName())).findFirst().orElse(null);
                if (ObjectUtil.isNotEmpty(config)) {
                    String url = config.getProValue();
                    Map<String, ClusterStateVO> map = openlookengClusterService.getMap(Arrays.asList(url));
                    if (CollectionUtil.isNotEmpty(map)) {
                        ClusterStateVO stateVO = map.get(ecs.getIp());
                        if (ObjectUtil.isNotEmpty(stateVO)) {
                            if (Constant.NODE_STATE_ACTIVE.getCode().equalsIgnoreCase(stateVO.getState())) {
                                ecs.setState(Constant.NODE_STATE_ACTIVE.getCode());
                            }
                        }
                    }
                }
            }
        }
        Cache cache = cacheManager.getCache(Constant.NODE_LOG_CACHE.getCode());
        if (ObjectUtil.isNotEmpty(cache)) {
            List<String> logList = cache.get(Constant.NODE_LOG_CACHE_KEY.getCode() + ecs.getId(), List.class);
            logFileQO.setLogFilePaths(logList);
            ecs.setLogFileQO(logFileQO);
        }
        Map<String, String> res = this.getOsInfoFromCache(ecs);
        String diskUsed = res.getOrDefault("disk_used", "0");
        String diskTotal = res.getOrDefault("disk_total", "0");
        String diskMount = res.getOrDefault("disk_mount", "0");
        String diskName = res.getOrDefault("disk_name", "0");
        String diskPercent = res.getOrDefault("disk_percent", "0");

        String[] diskNameSplit = StrUtil.split(diskName, "&");
        String[] diskUsedSplit = StrUtil.split(diskUsed, "&");
        String[] diskMountSplit = StrUtil.split(diskMount, "&");
        String[] diskTotalSplit = StrUtil.split(diskTotal, "&");
        String[] diskPercentSplit = StrUtil.split(diskPercent, "&");

        ArrayList<DiskQo> diskQos = new ArrayList<>();
        for (int i = 1; i < diskNameSplit.length; i++) {
            Double used = openlookengClusterServiceImpl.kbToGb(diskUsedSplit[i]);
            Double total = openlookengClusterServiceImpl.kbToGb(diskTotalSplit[i]);

            DiskQo diskQo = new DiskQo();
            diskQo.setDiskName(diskNameSplit[i]);
            diskQo.setDiskMount(diskMountSplit[i]);
            diskQo.setDiskPercent(StrUtil.removeSuffix(diskPercentSplit[i], "%"));
            diskQo.setDisk(used.toString() + "G/" + total + "G");
            diskQos.add(diskQo);
        }
        ecs.setDisks(diskQos);

        String cpuNum = res.getOrDefault("cpu_num", "0");
        //cpu 使用率
        String cpuUser = res.getOrDefault("cpu_user", "0");
        BigDecimal cpuNumVal = new BigDecimal(cpuNum);
        BigDecimal cpuUserVal = cpuNumVal.multiply(new BigDecimal(cpuUser)).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
        String memTotalStr = res.getOrDefault("mem_total", "0");
        Double memTotalVal = openlookengClusterServiceImpl.kbToGb(memTotalStr);
        String memSysUsedStr = res.getOrDefault("mem_sys_used", "0");
        Double memSysUsedVal = openlookengClusterServiceImpl.kbToGb(memSysUsedStr);

        ecs.setMemory(memSysUsedVal + "G/" + memTotalVal + "G");
        ecs.setCpu(cpuUser + "%");
        ecs.setJava(res.getOrDefault("java_version", "0"));
        ecs.setPy(res.getOrDefault("python_version", "0"));
        ecs.setSsh(res.getOrDefault("sshpass_version", "0"));

        return ecs;
    }

    @Override
    public void delete(List<Integer> ids)
    {
        QueryWrapper<OpenlookengCluster> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("ecs_id", ids);
        List<OpenlookengCluster> openlookengClusters = openlookengClusterMapper.selectList(queryWrapper);
        if (!openlookengClusters.isEmpty()) {
            List<Integer> nodeIds = openlookengClusters.stream().map(i -> i.getId()).collect(Collectors.toList());
            QueryWrapper<OpenlookengClusterConfig> query = new QueryWrapper<>();
            query.in("openlookeng_cluster_id", nodeIds);
            openlookengClusterConfigMapper.delete(query);
            try {
                openLookengServiceImpl.removeColonyOrNode(Constant.STOP.getCode(), nodeIds, true);
            }
            catch (Exception e) {
                log.error("err");
            }
            openlookengClusterMapper.deleteBatchIds(nodeIds);
        }
        this.baseMapper.deleteBatchIds(ids);
    }

    @Override
    public IPage<OpenlookengCluster> getCluster(Integer id, Integer pageNo, Integer pageSize)
    {
        IPage<OpenlookengCluster> page = new Page<>(pageNo, pageSize);
        QueryWrapper<OpenlookengCluster> wrapper = new QueryWrapper<>();
        wrapper.select("DISTINCT cluster_code");
        wrapper.eq("ecs_id", id);
        IPage<OpenlookengCluster> list = openlookengClusterMapper.selectPage(page, wrapper);

        list.getRecords().stream().forEach(i -> {
            i.setNode("节点");
            i.setVersion("版本");
            i.setRunningState("运行状态");
        });

        return list;
    }

    @Override
    public List<Ecs> analysisExcel(MultipartFile file, EcsDTO ecsDTO) throws Exception
    {
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        List<Ecs> ecss = new ArrayList<>();

        if (file != null) {
            File uploadFile = FileUploadUtils.getUploadFile(file, fileDir);
            List<ExcelColumnVo> vos = new ArrayList<>();
            vos.add(new ExcelColumnVo("主机名", "name"));
            vos.add(new ExcelColumnVo("账号", "userName"));
            vos.add(new ExcelColumnVo("密码", "passWord"));
            vos.add(new ExcelColumnVo("端口", "port"));
            vos.add(new ExcelColumnVo("管理IP", "ip"));
            vos.add(new ExcelColumnVo("业务IP", "serviceIp"));
            ecss = ExcelUtil.readExcel(uploadFile, vos, Ecs.class);
        }

        if (StrUtil.isNotBlank(ecsDTO.getName()) && StrUtil.isNotBlank(ecsDTO.getIp()) && StrUtil.isNotBlank(ecsDTO.getServiceIp()) && StrUtil.isNotBlank(ecsDTO.getPassWord()) && StrUtil.isNotBlank(ecsDTO.getUserName())) {
            Ecs ecs = new Ecs();
            BeanUtil.copyProperties(ecsDTO, ecs);
            ecss.add(ecs);
        }
        ecss = ecss.stream().collect(
                collectingAndThen(
                        toCollection(() -> new TreeSet<>(Comparator.comparing(Ecs::getIp))), ArrayList::new));
        List<Ecs> ecsList = new ArrayList<>();
        ecss.forEach(item -> {
            try {
                Ecs ecs = new Ecs();
                BeanUtil.copyProperties(item, ecs);
                ecs.setPassWord(Md5Utils.toAes(item.getPassWord()));
                ecsList.add(ecs);
            }
            catch (Exception e) {
                log.info("excel get fail,{}", e.getMessage());
            }
        });
        this.listOsInfo(ecsList);
        return ecss;
    }

    @Override
    public Ecs pingIp(EcsDTO ecsDTO)
    {
        Ecs ecs = new Ecs();
        BeanUtil.copyProperties(ecsDTO, ecs);
        ecs.setState(Constant.NODE_STATE_ACTIVE.getCode());
        //ping
        try {
            LinuxShellUtils.ping(ecs.getIp(), ecs.getPort());
        }
        catch (Exception e) {
            ecs.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
        }
        return ecs;
    }

    @Override
    public List<Ecs> getEcss(List<String> ips)
    {
        LambdaQueryWrapper<Ecs> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Ecs::getIp, ips);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<Ecs> listByUserId()
    {
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);
        Integer userId = Integer.valueOf(loginUserInfoDTO.getId());
        LambdaQueryWrapper<Ecs> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Ecs::getCreateUserId, userId);
        return this.list(queryWrapper);
    }

    @Override
    public List<Ecs> checkHost(List<EcsDTO> ecss)
    {
        List<Ecs> ecsList = ecss.stream().map(a -> {
            return a;
        }).collect(Collectors.toList());
        this.listOsInfo(ecsList);
        return ecsList;
    }

    @Override
    public List<Ecs> getAllUnboundHosts()
    {
        LoginUserInfoDTO loginUserInfoDTO = JwtTokenUtil.getCurrentLoginUser(audience);

        QueryWrapper<OpenlookengCluster> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("create_user_id", loginUserInfoDTO.getId());
        List<OpenlookengCluster> list = openlookengClusterMapper.selectList(queryWrapper);
        List<Integer> ecsIds = list.stream().distinct().map(i -> i.getEcsId()).collect(Collectors.toList());

        QueryWrapper<Ecs> wrapper = new QueryWrapper<>();
        wrapper.eq("create_user_id", loginUserInfoDTO.getId());
        if (ecsIds.size() != 0) {
            wrapper.notIn("id", ecsIds);
        }
        List<Ecs> ecsList = this.baseMapper.selectList(wrapper);

        return ecsList;
    }

    @Override
    public String logFileDownload(Integer ecsId, String fileName, HttpServletResponse response) throws Exception
    {
        Ecs ecs = this.baseMapper.selectById(ecsId);
        SshUserDTO sshUserDTO = new SshUserDTO();
        sshUserDTO.setSshHost(ecs.getIp());
        sshUserDTO.setSshPort(ecs.getPort());
        sshUserDTO.setSshUser(ecs.getUserName());
        sshUserDTO.setSshPass(Md5Utils.decrypt(ecs.getPassWord()));
        String downPath = FileConfig.getDownPath(ecs.getIp());
        FileUploadUtils.getAbsoluteFile(downPath, null);
        OpenlookengCluster openlookengCluster = openlookengClusterService.getByEcsId(ecs.getId());
        String path = openLookengServiceImpl.getDeployPath(openlookengCluster);
        String logPath = path + Constant.LOG_PATH.getCode();
        LinuxShellUtils.downSftpFile(sshUserDTO, logPath + fileName, downPath);
        return Constant.DOWN_PATH.getCode() + ecs.getIp() + "/" + fileName;
    }

    @Override
    public List<Map<String, String>> listOsInfo(List<Ecs> ecsList)
    {
        List<Map<String, String>> mapList = new ArrayList<>();
        CompletionService completionService = ThreadUtil.newCompletionService();
        ecsList.forEach(a -> {
            Callable<Map<String, String>> callableTask = () -> {
                try {
                    SshUserDTO sshUserDTO = new SshUserDTO();
                    sshUserDTO.setSshUser(a.getUserName());
                    sshUserDTO.setSshPass(Md5Utils.decrypt(a.getPassWord()));
                    sshUserDTO.setSshPort(a.getPort());
                    sshUserDTO.setSshHost(a.getIp());
                    a.setState(Constant.NODE_STATE_ACTIVE.getCode());
                    try {
                        LinuxShellUtils.ping(a.getIp(), a.getPort());
                    }
                    catch (Exception x) {
                        a.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
                    }
                    Map<String, String> res = new HashMap<>();
                    if (!a.getState().equalsIgnoreCase(Constant.NODE_STATE_SHUTTING_DOWN.getCode())) {
                        res = LinuxShellUtils.getOsInfo(sshUserDTO);
                        this.cacheOsInfo(a, res);
                        String distro = res.getOrDefault("distro", "");
                        if (StringUtils.isBlank(distro)) {
                            a.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
                        }
                        this.cacheNodeLog(a, sshUserDTO);
                    }
                    res.put("id", null != a.getId() ? a.getId().toString() : null);
                    return res;
                }
                catch (Exception e) {
                    Map<String, String> res = new HashMap<>();
                    res.put("id", a.getId().toString());
                    return res;
                }
            };
            completionService.submit(callableTask);
        });
        ecsList.forEach(a -> {
            try {
                Future<Map<String, String>> result = completionService.take();
                Map<String, String> res = result.get();
                mapList.add(res);
            }
            catch (Exception e) {
                Map<String, String> res = new HashMap<>();
                res.put("id", a.getId().toString());
                mapList.add(res);
                log.error("getOs InfoErr:{}", e.getMessage());
            }
        });
        return mapList;
    }

    private void cacheNodeLog(Ecs ecs, SshUserDTO sshUserDTO)
    {
        String key = Constant.NODE_LOG_CACHE_KEY.getCode() + ecs.getId();
        try {
            OpenlookengCluster openlookengCluster = openlookengClusterService.getByEcsId(ecs.getId());
            String path = openLookengServiceImpl.getDeployPath(openlookengCluster);
            String logPath = path + Constant.LOG_PATH.getCode();
            List<String> list = LinuxShellUtils.listFile(sshUserDTO, logPath);
            Cache cache = cacheManager.getCache(Constant.NODE_LOG_CACHE.getCode());
            if (CollectionUtil.isNotEmpty(list)) {
                cache.put(key, list);
            }
        }
        catch (Exception e) {
            log.info("get log fail,{}", e.getMessage());
        }
    }

    /**
     * @param ecs
     * @param osInfo
     */
    public void cacheOsInfo(Ecs ecs, Map<String, String> osInfo)
    {
        String key = "ecsCache_" + ecs.getId();
        Cache cache = cacheManager.getCache("ecsCache");
        cache.put(key, osInfo);
        Cache ecsCache = cacheManager.getCache(Constant.CHART_ECS_CACHE.getCode());
        List<Map<String, String>> cacheList = ecsCache.get(Constant.CHART_ECS_CACHE_KEY.getCode() + ecs.getId(), List.class);
        String format = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN);
        osInfo.put("time", format);
        if (CollectionUtil.isEmpty(cacheList)) {
            cacheList = new ArrayList<>();
        }
        else {
            if (cacheList.size() > 3600 * 24 * 30) {
                cacheList.remove(0);
            }
        }
        if (osInfo.size() > 2) {
            cacheList.add(osInfo);
        }
        ecsCache.put(Constant.CHART_ECS_CACHE_KEY.getCode() + ecs.getId(), cacheList);
    }

    @Override
    public Map<String, String> getOsInfoFromCache(Ecs ecs)
    {
        if (ecs == null) {
            return new HashMap<>();
        }
        if (ecs.getId() != null) {
            String key = "ecsCache_" + ecs.getId();
            Cache cache = cacheManager.getCache("ecsCache");
            Map<String, String> resCache = cache.get(key, Map.class);
            if (CollectionUtil.isNotEmpty(resCache)) {
                return resCache;
            }
        }
        SshUserDTO sshUserDTO = new SshUserDTO();
        sshUserDTO.setSshUser(ecs.getUserName());
        sshUserDTO.setSshPass(Md5Utils.decrypt(ecs.getPassWord()));
        sshUserDTO.setSshPort(ecs.getPort());
        sshUserDTO.setSshHost(ecs.getIp());
        Map<String, String> osInfo = LinuxShellUtils.getOsInfo(sshUserDTO);
        cacheOsInfo(ecs, osInfo);
        return osInfo;
    }

    @Override
    public List<Map<String, String>> cacheAllEcsInfo()
    {
        List<Ecs> ecsList = this.list();
        List<Map<String, String>> ecsInfoList = this.listOsInfo(ecsList);
        return ecsInfoList;
    }

    @Override
    public ClusterEchartDTO clusterEchartInfo(String queryType, Integer nodeId)
    {
        List<String> timeList = this.getCacheKey(queryType);
        Cache cache = cacheManager.getCache("clusterCache");
        List<Integer> nodeIdList = new ArrayList<>();
        if (nodeId == -1) {
            List<OpenlookengCluster> clusterList = openlookengClusterService.listCurrentUserCluster();
            nodeIdList = clusterList.stream().map(a -> a.getId()).collect(Collectors.toList());
        }
        else {
            nodeIdList.add(nodeId);
        }
        List<EchartTimeDTO> cpuInfoListAll = new ArrayList<>();
        List<EchartTimeDTO> menInfoListAll = new ArrayList<>();
        List<EchartTimeDTO> diskInfoListAll = new ArrayList<>();
        nodeIdList.forEach(a -> {
            String cpuInfoListCacheKey = "clusterCacheEchart_cpuInfoList_" + a;
            String menInfoListCacheKey = "clusterCacheEchart_menInfoList_" + a;
            String diskInfoListCacheKey = "clusterCacheEchart_diskInfoList_" + a;
            List<EchartTimeDTO> cpuInfoList = cache.get(cpuInfoListCacheKey, List.class);
            List<EchartTimeDTO> diskInfoList = cache.get(diskInfoListCacheKey, List.class);
            List<EchartTimeDTO> menInfoList = cache.get(menInfoListCacheKey, List.class);
            if (cpuInfoList == null) {
                cpuInfoList = new ArrayList<>();
            }
            if (menInfoList == null) {
                menInfoList = new ArrayList<>();
            }
            if (diskInfoList == null) {
                diskInfoList = new ArrayList<>();
            }
            if (!cpuInfoList.isEmpty()) {
                cpuInfoListAll.addAll(cpuInfoList);
            }
            if (!menInfoList.isEmpty()) {
                menInfoListAll.addAll(menInfoList);
            }
            if (!diskInfoList.isEmpty()) {
                diskInfoListAll.addAll(diskInfoList);
            }
        });
        ClusterEchartDTO clusterEchartDTO = new ClusterEchartDTO();
        List<EchartTimeDTO> cpuInfoList = timeList.stream().map(a -> {
            Date time = cn.hutool.core.date.DateUtil.parse(a, "yyyy-MM-dd HH:mm:ss");
            BigDecimal total = BigDecimal.ZERO;
            List<EchartTimeDTO> echartTimeDTOS = cpuInfoListAll.stream().filter(y -> {
                return y.getCacheTime().getTime() <= time.getTime();
            }).collect(Collectors.toList());
            if (!echartTimeDTOS.isEmpty()) {
                for (EchartTimeDTO echartTimeDTO : echartTimeDTOS) {
                    total = total.add(echartTimeDTO.getValue());
                }
                BigDecimal perCent = total.divide(new BigDecimal(echartTimeDTOS.size()), 2, RoundingMode.HALF_UP); //.multiply(multiplyNum);
                EchartTimeDTO cpuDTO = new EchartTimeDTO();
                cpuDTO.setTime(a);
                cpuDTO.setValue(perCent);
                return cpuDTO;
            }
            else {
                EchartTimeDTO cpuDTO = new EchartTimeDTO();
                cpuDTO.setTime(a);
                cpuDTO.setValue(BigDecimal.ZERO);
                return cpuDTO;
            }
        }).collect(Collectors.toList());

        List<EchartTimeDTO> menInfoList = timeList.stream().map(a -> {
            Date time = cn.hutool.core.date.DateUtil.parse(a, "yyyy-MM-dd HH:mm:ss");
            BigDecimal total = BigDecimal.ZERO;
            List<EchartTimeDTO> echartTimeDTOS = menInfoListAll.stream().filter(y -> {
                return y.getCacheTime().getTime() <= time.getTime();
            }).collect(Collectors.toList());
            if (!echartTimeDTOS.isEmpty()) {
                for (EchartTimeDTO echartTimeDTO : echartTimeDTOS) {
                    total = total.add(echartTimeDTO.getValue());
                }
                BigDecimal perCent = total.divide(new BigDecimal(echartTimeDTOS.size()), 2, RoundingMode.HALF_UP); //.multiply(multiplyNum);
                EchartTimeDTO cpuDTO = new EchartTimeDTO();
                cpuDTO.setTime(a);
                cpuDTO.setValue(perCent);
                return cpuDTO;
            }
            else {
                EchartTimeDTO cpuDTO = new EchartTimeDTO();
                cpuDTO.setTime(a);
                cpuDTO.setValue(BigDecimal.ZERO);
                return cpuDTO;
            }
        }).collect(Collectors.toList());

        List<EchartTimeDTO> diskInfoList = timeList.stream().map(a -> {
            Date time = cn.hutool.core.date.DateUtil.parse(a, "yyyy-MM-dd HH:mm:ss");
            BigDecimal total = BigDecimal.ZERO;
            List<EchartTimeDTO> echartTimeDTOS = diskInfoListAll.stream().filter(y -> {
                return y.getCacheTime().getTime() <= time.getTime();
            }).collect(Collectors.toList());
            if (!echartTimeDTOS.isEmpty()) {
                for (EchartTimeDTO echartTimeDTO : echartTimeDTOS) {
                    total = total.add(echartTimeDTO.getValue());
                }
                BigDecimal perCent = total.divide(new BigDecimal(echartTimeDTOS.size()), 2, RoundingMode.HALF_UP); //.multiply(multiplyNum);
                EchartTimeDTO cpuDTO = new EchartTimeDTO();
                cpuDTO.setTime(a);
                cpuDTO.setValue(perCent);
                return cpuDTO;
            }
            else {
                EchartTimeDTO cpuDTO = new EchartTimeDTO();
                cpuDTO.setTime(a);
                cpuDTO.setValue(BigDecimal.ZERO);
                return cpuDTO;
            }
        }).collect(Collectors.toList());
        clusterEchartDTO.setCpuInfoList(cpuInfoList);
        clusterEchartDTO.setMenInfoList(menInfoList);
        clusterEchartDTO.setDiskInfoList(diskInfoList);
        return clusterEchartDTO;
    }

    @Override
    public Map<String, Map<String, String>> getHostItem(String queryType, String ecsId)
    {
        Map<String, Map<String, String>> typeMap = new HashMap<>();
        LinkedHashMap<String, String> cpuTimeMap = new LinkedHashMap<>();
        LinkedHashMap<String, String> ramTimeMap = new LinkedHashMap<>();
        LinkedHashMap<String, String> diskTimeMap = new LinkedHashMap<>();
        LinkedHashMap<String, String> netRateMap = new LinkedHashMap<>();

        List<Ecs> ecsList = this.listByUserId();
        List<String> queryKey = this.getCacheKey(queryType);
        Cache cache = cacheManager.getCache(Constant.CHART_ECS_CACHE.getCode());
        Cache netRateCache = cacheManager.getCache(Constant.NET_RATE_CACHE_NAME.getCode());

        List<String> ecsIds = new ArrayList<>();
        if (StrUtil.isEmpty(ecsId)) {
            ecsIds.addAll(ecsList.stream().map(item -> String.valueOf(item.getId())).distinct().collect(Collectors.toList()));
        }
        else {
            ecsIds.add(ecsId);
        }
        List<Map<String, String>> totalCacheList = new ArrayList<>();
        Map<String, Map<String, String>> totalNetCacheList = new HashMap<>();
        ecsIds.forEach(item -> {
            List<Map<String, String>> list = cache.get(Constant.CHART_ECS_CACHE_KEY.getCode() + item, List.class);
            Map<String, Map<String, String>> netList = netRateCache.get(Constant.NET_RATE_CACHE_KEY.getCode() + item, Map.class);
            if (CollectionUtil.isNotEmpty(list)) {
                totalCacheList.addAll(list);
            }
            if (CollectionUtil.isNotEmpty(netList)) {
                totalNetCacheList.putAll(netList);
            }
        });
        Double[] totalRam = new Double[]{0d};
        Double[] userRam = new Double[]{0d};
        Double[] totalCpu = new Double[]{0d};
        Double[] useCpu = new Double[]{0d};
        Double[] totalDisk = new Double[]{0d};
        Double[] useDisk = new Double[]{0d};
        //cpu总核数/cpu空闲百分比/内存总量/操作系统已使用内存总量/已使用交换分区大小/磁盘使用量
        String cpuNum = null;
        String cpuUser = null;
        String memTotal = null;
        String memSysUsed = null;
        String diskUsed = null;
        String diskTotal = null;
        int[] index = new int[]{0};
        Map<String, String> totalNets = new HashMap<>();
        List<Map<String, String>> sortList = new ArrayList<>();
        for (String ite : queryKey) {
            Date queryTime = DateUtil.parse(ite);
            List<String> keys = totalNetCacheList.keySet().stream().filter(item -> DateUtil.format(queryTime, Constant.YMDH.getCode()).equalsIgnoreCase(item)).collect(Collectors.toList());
            keys.forEach(k -> {
                totalNets.putAll(totalNetCacheList.get(k));
            });
            LinkedHashMap<String, String> finalMap = totalNets.entrySet().stream().sorted(Map.Entry.comparingByKey())
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new));
            for (Map.Entry<String, String> item : finalMap.entrySet()) {
                Map<String, String> map = new HashMap<>();
                map.put(item.getKey(), item.getValue());
                sortList.add(map);
            }
            List<String> netRates = new ArrayList<>();
            for (int j = 0; j < sortList.size(); j++) {
                Map<String, String> start = sortList.get(j);
                Map<String, String> end = sortList.get(j == (sortList.size() - 1) ? j : (j + 1));
                Date startTime = DateUtil.parse(start.keySet().stream().findFirst().get());
                Date endTime = DateUtil.parse(end.keySet().stream().findFirst().get());
                if ((!queryTime.before(startTime) && queryTime.before(endTime)) || (j == (sortList.size() - 1))) {
                    String s = start.values().stream().findFirst().get();
                    netRates.add(s);
                }
            }
            BigDecimal reduce = netRates.stream().map(item -> new BigDecimal(item)).reduce(BigDecimal.ZERO, BigDecimal::add);
            netRateMap.put(ite, reduce + "");

            for (int i = 0; i < totalCacheList.size(); i++) {
                index[0] = i;
                Map<String, String> start = totalCacheList.get(i);
                Map<String, String> end = totalCacheList.get(i == (totalCacheList.size() - 1) ? i : i + 1);
                Date startTime = DateUtil.parse(start.get("time"));
                Date endTime = DateUtil.parse(end.get("time"));
                //Filter data that is greater than or equal to the start time and less than the end time
                if ((!queryTime.before(startTime) && queryTime.before(endTime)) || (i == totalCacheList.size() - 1)) {
                    cpuNum = start.getOrDefault("cpu_num", "0");
                    cpuUser = start.getOrDefault("cpu_user", "0");
                    memTotal = start.getOrDefault("mem_total", "0");
                    memSysUsed = start.getOrDefault("mem_sys_used", "0");
                    diskTotal = start.getOrDefault("disk_total", "0");
                    diskUsed = start.getOrDefault("disk_used", "0");

                    if (StrUtil.isBlank(cpuNum)) {
                        cpuNum = "0";
                    }
                    if (StrUtil.isBlank(cpuUser)) {
                        cpuUser = "0";
                    }
                    if (StrUtil.isBlank(memTotal)) {
                        memTotal = "0";
                    }
                    if (StrUtil.isBlank(memSysUsed)) {
                        memSysUsed = "0";
                    }
                    if (StrUtil.isBlank(diskTotal)) {
                        diskTotal = "0";
                    }
                    if (StrUtil.isBlank(diskUsed)) {
                        diskUsed = "0";
                    }

                    totalCpu[0] += Double.parseDouble(cpuNum);
                    useCpu[0] += (Double.parseDouble(cpuUser) / 100 * Double.parseDouble(cpuNum));
                    totalRam[0] += Double.parseDouble(memTotal);
                    userRam[0] += Double.parseDouble(memSysUsed);
                    totalDisk[0] += Arrays.stream(StrUtil.split(diskTotal, "&")).skip(1).map(item -> Double.parseDouble(item)).collect(Collectors.summingDouble(v -> v));
                    useDisk[0] += Arrays.stream(StrUtil.split(diskUsed, "&")).skip(1).map(item -> Double.parseDouble(item)).collect(Collectors.summingDouble(v -> v));
                }
            }
            cpuTimeMap.put(ite, totalCpu[0] != 0 ? Double.valueOf(String.format("%.2f", (useCpu[0] / totalCpu[0] * 100))) + "" : "0");
            ramTimeMap.put(ite, totalRam[0] != 0 ? Double.valueOf(String.format("%.2f", (userRam[0] / totalRam[0] * 100))) + "" : "0");
            diskTimeMap.put(ite, totalDisk[0] != 0 ? Double.valueOf(String.format("%.2f", (useDisk[0] / totalDisk[0] * 100))) + "" : "0");
        }
        typeMap.put("cpu", cpuTimeMap);
        typeMap.put("ram", ramTimeMap);
        typeMap.put("disk", diskTimeMap);
        typeMap.put("netRate", netRateMap);
        return typeMap;
    }

    @Override
    public List<String> getCacheKey(String type)
    {
        String pattern = DatePattern.NORM_DATETIME_PATTERN;
        Date date = new Date();
        String hms;
        List<String> list = new ArrayList<>(); //Key set to query
        int average = 13; //平均等分13份
        switch (type) {
            case "0"://The average score was 13
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetSecond(date, i * (-1)), pattern);
                    list.add(0, hms);
                }
                break;
            case "1"://1 hour
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetMinute(date, i * (-5)), pattern);
                    list.add(0, hms);
                }
                break;
            case "2"://2hour
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetMinute(date, i * (-10)), pattern);
                    list.add(0, hms);
                }
                break;
            case "3"://6hour
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetMinute(date, i * (-30)), pattern);
                    list.add(0, hms);
                }
                break;
            case "4"://12hour
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetHour(date, i * (-1)), pattern);
                    list.add(0, hms);
                }
                break;
            case "5"://one day
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetHour(date, i * (-2)), pattern);
                    list.add(0, hms);
                }
                break;
            case "6"://a week
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetHour(date, i * (-14)), pattern);
                    list.add(0, hms);
                }
                break;
            case "7"://a month
                for (int i = 0; i < average; i++) {
                    hms = DateUtil.format(DateUtil.offsetHour(date, i * (-60)), pattern);
                    list.add(0, hms);
                }
                break;
        }
        return list;
    }

    @Override
    public void cacheNetRate()
    {
        List<Ecs> ecsList = this.list();
        ecsList.forEach(a -> {
            TreadUtils.execute(() -> {
                this.getHostNetRate(a);
            });
        });
    }

    private void getHostNetRate(Ecs a)
    {
        String cmd = LinuxShellUtils.shellPath + "getNetItem.sh";
        try {
            String res;
            a.setState(Constant.NODE_STATE_ACTIVE.getCode());
            Session session = JschSessionPool.INSTANCE.get(a.getIp());
            if (ObjectUtil.isEmpty(session)) {
                SshUserDTO sshUserDTO = new SshUserDTO();
                sshUserDTO.setSshUser(a.getUserName());
                sshUserDTO.setSshPass(Md5Utils.decrypt(a.getPassWord()));
                sshUserDTO.setSshPort(a.getPort());
                sshUserDTO.setSshHost(a.getIp());
                try {
                    session = JschUtil.createSession(sshUserDTO.getSshHost(), sshUserDTO.getSshPort(), sshUserDTO.getSshUser(), sshUserDTO.getSshPass());
                    session.connect(5000);
                    JschSessionPool.INSTANCE.put(a.getIp(), session);
                }
                catch (Exception e) {
                    JschSessionPool.INSTANCE.close(a.getIp());
                    log.info("ecs:{},connect fail >>>,err:{}", a.getIp(), e.getMessage());
                    a.setState(Constant.NODE_STATE_SHUTTING_DOWN.getCode());
                }
            }
            if (!a.getState().equalsIgnoreCase(Constant.NODE_STATE_SHUTTING_DOWN.getCode())) {
                res = JschUtil.exec(session, cmd, Charset.defaultCharset());
                Cache cache = cacheManager.getCache(Constant.NET_RATE_CACHE_NAME.getCode());
                Map<String, Map<String, String>> mapHour = new ConcurrentHashMap<>();
                Map<String, String> mapSec = new ConcurrentHashMap<>();
                if (StrUtil.isNotEmpty(res)) {
                    res = res.replaceAll("\\n", "");
                    String[] infos = res.split("kb/s");
                    BigDecimal reduce = Arrays.stream(infos).map(item -> new BigDecimal(item.trim())).reduce(BigDecimal.ZERO, BigDecimal::add);
                    Map<String, Map<String, String>> list = cache.get(Constant.NET_RATE_CACHE_KEY.getCode() + a.getId(), Map.class);
                    Date date = new Date();
                    String hms = DateUtil.format(date, DatePattern.NORM_DATETIME_PATTERN);
                    String h = DateUtil.format(date, Constant.YMDH.getCode());
                    if (CollectionUtil.isNotEmpty(list)) {
                        Map<String, String> val = list.get(h);
                        if (CollectionUtil.isNotEmpty(val)) {
                            mapSec.putAll(val);
                        }
                    }
                    mapSec.put(hms, reduce + "");
                    mapHour.put(h, mapSec);
                    cache.put(Constant.NET_RATE_CACHE_KEY.getCode() + a.getId(), mapHour);
                }
            }
        }
        catch (Exception e) {
            JschSessionPool.INSTANCE.close(a.getIp());
        }
    }
}
